package com.google.code.struts2jruby.ognl;

import ognl.OgnlException;
import ognl.PropertyAccessor;
import org.jruby.Ruby;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.builtin.IRubyObject;

import java.util.Map;

/**
 * This custom PropertyAccessor interfaces with the JRuby internal API in order
 * to set/get the value of properties.
 *
 * @author Richard L. Burton III
 * @see ognl.PropertyAccessor
 */
public class RubyObjectPropertyAccessor implements PropertyAccessor {

    public Object getProperty(Map map, Object object, Object property) throws OgnlException {
        IRubyObject ro = (IRubyObject) object;
        Ruby runtime = ro.getRuntime();
        return ro.callMethod(runtime.getCurrentContext(), toGetSyntax((String) property));
    }

    /**
     * TODO: Handle <script>:1: undefined method `age=' for nil:NilClass (NoMethodError)
     */
    public void setProperty(Map map, Object instance, Object property, Object value) throws OgnlException {
        // Pseudo logic.
        // if property is NilClass
        //      Create an Instance of JRubyObject
        //      Set the value
        //      update the instance

        IRubyObject ro = (IRubyObject) instance;
        Ruby runtime = ro.getRuntime();
        IRubyObject rubyValue = JavaEmbedUtils.javaToRuby(runtime, value);
        ro.callMethod(runtime.getCurrentContext(), toSetSyntax((String) property), rubyValue);
    }

    /**
     * This method handles creating the Ruby set syntax.
     * @param property The property to set.
     * @return The Ruby syntax for setting the property.
     */
    protected String toSetSyntax(String property) {
        return property + '=';
    }

    /**
     * This method handles creating the Ruby get syntax. This method exist
     * in case someone uses this class as a base class and want's to alter
     * the syntax.
     * @param property The property to get.
     * @return Returns the Ruby get syntax.
     */
    protected String toGetSyntax(String property) {
        return property;
    }

}
